//客户端：实现给服务端发送数据即可：
#include<iostream>
#include<cstdlib>
#include<unistd.h>
#include<string.h>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
using namespace std;

//提醒用户如何使用客户端
void Usage(string proc)
{
    cout<<"./Usage:"<<proc<<"server_ip server_port\n"<<endl;
}

//我们的客户端设计成使用命令行参数来自由设定ip地址和端口号
int main(int argc,char*argv[])
{   
    if(argc!=3)
    {
        Usage(argv[0]);//是可执行程序的名字（带有路径）
        exit(0);
    }
    string server_ip=argv[1];//先把ip地址保存，稍后进一步处理
    uint16_t server_port=stoi(argv[2]);//端口号直接转为16位的整形即可

    struct sockaddr_in server;//创建一个结构体保存服务器地址信息
    //经典流程：
    bzero(&server,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(server_port);
    server.sin_addr.s_addr=inet_addr(server_ip.c_str());//它用于将一个点分十进制的 IPv4 地址字符串转换为网络字节序的二进制值
    socklen_t len=sizeof(server);

    //开始创建套接字：
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd<0)
    {
        cout<<"socker error"<<endl;
        return 1;
    }
    
    //客户端要bind吗？必须要！，只不过不用显示的bind，一般由OS自由随机选择
    //一个端口号只能被一个进程bind，但是一个进程可以有多个端口号
    //系统会在首次发送数据的时候帮我们bind绑定

    //bind将我们的进程ip地址端口号和套接字绑定起来这样从该套接字对应的文件描述符对应的文件中获取的信息才能狗知道发送到绑定该套接字的的进程
    
    string msg;
    char buffer[1024];
    while(true)
    {
        cout<<"Please Enter@ ";
        getline(cin,msg);//输入一行数据给msg，getline函数用来输入一行数据给一个string类型

        //注意：string的size（）函数返回值包括末尾的\0一共的字符数量
        sendto(sockfd,msg.c_str(),msg.size(),0,(struct sockaddr*)&server,len);//首次发送数据的时候OS会帮客户端绑定客户端与套接字
        //将数据发送给命令行参数传回来的地址对应的服务器


        //在准备接收服务器传来的数据，并且记录下服务器的地址信息
        struct sockaddr_in temp;
        socklen_t len=sizeof(temp);
        ssize_t s=recvfrom(sockfd,buffer,1023,0,(struct sockaddr*)&temp,&len);
        if(s>0)
        {
            buffer[s]=0;
            cout<<buffer<<endl;
        }

    }
    //客户端结束关闭对应的文件描述符：
    close(sockfd);

    return 0;
}
